package com.tsd.core.datasource;

import cn.hutool.core.util.PageUtil;
import cn.hutool.db.*;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson.JSON;
import com.tsd.core.config.DataSourceConfig;
import com.tsd.core.constants.Constants;
import com.tsd.core.utils.ExceptionUtil;
import com.tsd.core.utils.HlpUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName: DataSourceInitService
 * @Description: 初始化数据源
 * @Author:
 */
@Component
@PropertySource(value = {"classpath:db.properties"}, ignoreResourceNotFound = true)
public class DataSourceInitService {

    private static final Logger LOGGER = LoggerFactory.getLogger("quartzLogger");

    // 保存动态创建的数据源
    private static final Map<Object, Entity> TARGET_ACCOUNT_SET = new ConcurrentHashMap<>();

    @Value("${tsd.multiDb}")
    private boolean multiDb;
    @Value("${tsd.master.mode}")
    private String masterMode;

    @Resource
    private DruidDataSource masterDataSource;
    @Resource
    private DataSourceConfig dataSourceConfig;

    @PostConstruct
    public void initDataSourcePool() {
        TARGET_ACCOUNT_SET.clear();
        try {
            // 加入主库数据源
            Entity masterEntity = DataSourceUtils.gen4Master(masterDataSource, dataSourceConfig.getDataSourceProperties());
            if (!this.multiDb && !HlpUtils.isEmpty(this.masterMode)) {
                String[] modes = this.masterMode.replaceAll("，", ",").split(",");
                masterEntity.put("mode", JSON.toJSONString(Arrays.asList(modes)));
            }
            this.initDataSource(masterEntity);
        } catch (Exception e) {
            LOGGER.error("初始化主库数据源失败：{}", e.getMessage());
        }
        if (!multiDb) {
            return;
        }
        // 判断主数据源中是否存在表sys_account_set
        if (!DataSourceUtils.isTableExist(this.masterDataSource, Constants.TABLE_NAME_SYS_ACCOUNT_SET)) {
            return;
        }
        Db db = DbUtil.use(this.masterDataSource);
        int index = 1;
        int pageSize = 100;
        PageUtil.setOneAsFirstPageNo();
        String sql = "SELECT * FROM sys_account_set WHERE dr=0 AND state=2";
        while (true) {
            Page page = new Page(index, pageSize);
            try {
                PageResult<Entity> result = db.page(sql, page);
                for (Entity entity : result) {
                    if (HlpUtils.isEmpty(entity.getStr("db_url"))) {
                        continue;
                    }
                    String sid = entity.getStr("sid");
                    if (DynamicDataSource.checkExist(sid)) {
                        continue;
                    }
                    this.initDataSource(entity);
                    LOGGER.info("初始化数据源：" + sid);
                }
                if (result.size() < pageSize) {
                    break;
                }
                index++;
            } catch (Exception e) {
                LOGGER.error(ExceptionUtil.getStackTraceFromException(e));
                break;
            }
        }
    }

    public void initDataSource(Entity entity) {
        String sid = entity.getStr("sid");
        String code = entity.getStr("code");
        if (DataSourceContextHolder.DEFAULT_ACCOUNT_SET_SID.equals(sid)) {
            DynamicDataSource.addDynamicDataSource(DataSourceContextHolder.DEFAULT_ACCOUNT_SET_SID, masterDataSource);
        } else {
            DataSource dataSource = DataSourceUtils.newDataSource(entity, false);
            DynamicDataSource.addDynamicDataSource(code, dataSource);
        }
        entity.put("log", false);
        TARGET_ACCOUNT_SET.put(code, entity);
        // 创建日志数据源
        Entity logEntity = DataSourceUtils.copy4Log(entity);
        String logCode = logEntity.getStr("code");
        DataSource logDataSource = DataSourceUtils.newDataSource(logEntity, false);
        DynamicDataSource.addDynamicDataSource(logCode, logDataSource);
        TARGET_ACCOUNT_SET.put(logCode, logEntity);
    }

    public static Entity getAccountSet(Object key) {
        return TARGET_ACCOUNT_SET.get(key);
    }

    public static Entity getAccountSet(Long id) {
        Entity accountSetExt = null;
        for (Entity entity : TARGET_ACCOUNT_SET.values()) {
            Long entityId = entity.getLong("id");
            if (!HlpUtils.isEmpty(entityId) && entityId.equals(id)) {
                accountSetExt = entity;
                break;
            }
        }
        return accountSetExt;
    }

    public static Map<Object, Entity> getAccountSetMap() {
        return TARGET_ACCOUNT_SET;
    }

    public DataSourceProperties getDataSourceProperties() {
        return dataSourceConfig.getDataSourceProperties();
    }
}
